#include <vector>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <iostream>
#include <cstdlib>
#include <time.h>

#define protected public
#define private public

#undef private
#undef protected

#include "acl_rt.h"
#include "runtime/base.h"
#include "runtime/mem.h"

using namespace std;
using namespace testing;

class AclTest : public testing::Test {
protected:
  void SetUp(){}
  void TearDown(){}
};

TEST_F(AclTest, aclrtMalloc_sizeInvalid) {
  void *devPtr = NULL;
  size_t size = (size_t)(-1);
  aclError ret = aclrtMalloc(&devPtr, size, ACL_MEM_MALLOC_NORMAL_ONLY);
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);

  size = (size_t)(0);
  ret = aclrtMalloc(&devPtr, size, ACL_MEM_MALLOC_NORMAL_ONLY);
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
}

TEST_F(AclTest, aclrtMalloc_devPtrInvalid) {
  aclError ret = aclrtMalloc(NULL, 1, ACL_MEM_MALLOC_HUGE_FIRST);
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
}

TEST_F(AclTest, aclrtMalloc_policyNotSupported) {
  void *devPtr = NULL;
  size_t size = 1;
  // not support p2p scenes.
  aclError ret = aclrtMalloc(&devPtr, size, ACL_MEM_MALLOC_HUGE_FIRST_P2P);
  EXPECT_EQ(ret, ACL_ERROR_FEATURE_UNSUPPORTED);
  ret = aclrtMalloc(&devPtr, size, (aclrtMemMallocPolicy)(ACL_MEM_TYPE_HIGH_BAND_WIDTH | ACL_MEM_MALLOC_NORMAL_ONLY_P2P));
  EXPECT_EQ(ret, ACL_ERROR_FEATURE_UNSUPPORTED);
}

TEST_F(AclTest, aclrtMalloc_policyInvalid) {
  void *devPtr = NULL;
  size_t size = 1;
  aclError ret = aclrtMalloc(&devPtr, size, (aclrtMemMallocPolicy)0xffff);
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
}

TEST_F(AclTest, aclrtMalloc_normal_singlePageType) {
  void *devPtr = NULL;
  size_t size = 1;
  aclError ret = aclrtMalloc(&devPtr, size, ACL_MEM_MALLOC_HUGE_FIRST);
  EXPECT_EQ(ret, ACL_SUCCESS);
  ret = aclrtFree(devPtr);
  EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(AclTest, aclrtMalloc_normal_singleMemoryType) {
  void *devPtr = NULL;
  size_t size = 1;
  // memory type is DDR
  aclError ret = aclrtMalloc(&devPtr, size, ACL_MEM_TYPE_HIGH_BAND_WIDTH);
  EXPECT_EQ(ret, ACL_SUCCESS);
  ret = aclrtFree(devPtr);
  EXPECT_EQ(ret, ACL_SUCCESS);

  // memory type is HBM
  ret = aclrtMalloc(&devPtr, size, ACL_MEM_TYPE_LOW_BAND_WIDTH);
  EXPECT_EQ(ret, ACL_SUCCESS);
  ret = aclrtFree(devPtr);
  EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(AclTest, aclrtMalloc_normal_mixedMemoryType) {
  void *devPtr = NULL;
  size_t size = 1;
  // policy contain both low and high width type, warn!.
  aclError ret = aclrtMalloc(&devPtr, size, (aclrtMemMallocPolicy)(ACL_MEM_TYPE_HIGH_BAND_WIDTH | ACL_MEM_TYPE_LOW_BAND_WIDTH));
  EXPECT_EQ(ret, ACL_SUCCESS);
  ret = aclrtFree(devPtr);
  EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(AclTest, memory_free_device) {
  void *devPtr = (void *)0x01;
  aclError ret = aclrtFree(NULL);
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
  ret = aclrtMalloc(&devPtr, 1, ACL_MEM_MALLOC_HUGE_ONLY);
  EXPECT_EQ(ret, ACL_SUCCESS);
  ret = aclrtFree(devPtr);
  EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(AclTest, aclrtMemSet_paramInvalid) {
    // 1. devPtr is NULL
    aclError ret = aclrtMemset(NULL, 1, 1, 1);
    EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
    // 2. param count > maxCount
    void *ptr = (void *)0x01;
    ret = aclrtMemset(ptr, 1, 1, 2);
    EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
}

TEST_F(AclTest, aclrtMemSet_normal) {
    void *ptr = (void *)0x01;
    aclError ret = aclrtMemset(ptr, 1, 1, 1);
    EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(AclTest, aclrtMemcpy_paramNULL) {
  void *src = (void *)0x02;
  aclError ret = aclrtMemcpy(NULL, 1, src, 1, ACL_MEMCPY_HOST_TO_HOST);
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);

  void *dst = (void *)0x01;
  ret = aclrtMemcpy(dst, 1, NULL, 1, ACL_MEMCPY_HOST_TO_HOST);
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
}

TEST_F(AclTest, aclrtMemcpy_kindInvalid) {
  void *dst = (void *)0x01;
  void *src = (void *)0x02;
  aclError ret = aclrtMemcpy(dst, 1, src, 1, (aclrtMemcpyKind)0x7FFFFFFFF);
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
}

TEST_F(AclTest, aclrtMemcpy_countInvalid) {
  void *dst = (void *)0x01;
  void *src = (void *)0x02;
  // count is greater than destMax
  aclError  ret = aclrtMemcpy(dst, 1, src, 2, ACL_MEMCPY_HOST_TO_HOST);
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
}

TEST_F(AclTest, aclrtMemcpy_normal_ToHost) {
  void *dst = (void *)0x01;
  void *src = (void *)0x02;
  aclError ret = aclrtMemcpy(dst, 1, src, 1, ACL_MEMCPY_HOST_TO_HOST);
  EXPECT_EQ(ret, ACL_SUCCESS);

  ret = aclrtMemcpy(dst, 1, src, 1, ACL_MEMCPY_DEVICE_TO_HOST);
  EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(AclTest, aclrtMemcpy_normal_ToDevice) {
  void *dst = (void *)0x01;
  void *src = (void *)0x02;
  aclError ret = aclrtMemcpy(dst, 1, src, 1, ACL_MEMCPY_HOST_TO_DEVICE);
  EXPECT_EQ(ret, ACL_SUCCESS);

  ret = aclrtMemcpy(dst, 1, src, 1, ACL_MEMCPY_DEVICE_TO_DEVICE);
  EXPECT_EQ(ret, ACL_SUCCESS);
}

TEST_F(AclTest, aclrtGetMemInfo_ParamNULL) {
  size_t free;
  aclError ret = aclrtGetMemInfo(ACL_DDR_MEM_HUGE, &free, NULL);
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
  size_t total;
  ret = aclrtGetMemInfo(ACL_DDR_MEM_HUGE, NULL, &total);
  EXPECT_EQ(ret, ACL_ERROR_INVALID_PARAM);
}

TEST_F(AclTest, aclrtGetMemInfo_attrInvalid) {
  size_t free;
  size_t total;
  aclError ret = aclrtGetMemInfo((aclrtMemAttr)0x1000, &free, &total);
  EXPECT_EQ(ret, ACL_ERROR_RT_INVALID_MEMORY_TYPE);
}

TEST_F(AclTest, aclrtGetMemInfo_normal) {
  size_t free;
  size_t total;
  aclError ret = aclrtGetMemInfo(ACL_DDR_MEM_HUGE, &free, &total);
  EXPECT_EQ(ret, ACL_SUCCESS);
}